package ca.uvic.group2.server;

import java.util.*; 
import java.sql.*;
import java.io.*; 
import java.io.Serializable;
//import javax.sql.*;
//import org.postgresql.jdbc3.*;
import ca.uvic.group2.api.*;
import ca.uvic.group2.api.exceptions.*;

public class JDBCConnectionImpl 
{ 
	
	private Connection conn; // the precious connection 
	
	private JDBCConnectionImpl () throws SQLException
	{
		conn = DriverManager.getConnection("jdbc:postgresql://b02.seng.engr.uvic.ca/se462g02","se462g02","mvbrioeE");
		System.out.println("JDBCConnectionImpl: finish jdbcconnectionimpl CREATION!");
		return; 	
	}
		
	Connection getConnection()
	{
		return conn;
	}
	
	void close()
	{
		try
		{
			conn.close();
		}
		catch(SQLException sqle)
		{
			System.out.println("close: sqle" + sqle);
			
		}
	}
	
	//free resources when object is destroyed
	protected void finalize() throws SQLException
	{
		close();
	}
	
		//Pool class
		static class JDBCPool 
		{
			// dictionary of database names with corresponding vector of connections 
			//private Hashtable poolDictionary = new Hashtable();
			private Vector pool;
			private int MAX_CONN = 8;
			private int curConn = -1;
			
			//methods and attributes of Singelton pattern
			//private constructor
			private JDBCPool() {}
			//get class instance;
			private static JDBCPool _instance;
			
			//Singleton getter utilizing Double Checked Locking pattern
			public static JDBCPool getInstance()
			{
				if (_instance == null)
				{
					synchronized(JDBCPool.class)
					{
						if(_instance == null)
							_instance = new JDBCPool();												
					}
				}
				return _instance;
			}
			
			//get connection from pool
			public synchronized JDBCConnectionImpl acquireImpl() throws SQLException, ClassNotFoundException, PoolException
			{
				try{
		            Class.forName("org.postgresql.Driver");
		        }
		        catch (ClassNotFoundException cnfe)
		        {
		            System.out.println("Class not found blargh!");
					throw new ClassNotFoundException("Class!" + cnfe);
		            //return ;
		        }
				
				if(curConn == -1)
				{
					System.out.println("acquireImpl: init currConn to 0");					
					curConn = 0;
				}
				
				//get connection pool
				if(pool != null)
				{
					int size = pool.size();
					System.out.println("current pool size:" + size);
					
					if(size > 0)
					{
						System.out.println("acquireImpl: get a connection from the pool");						
						JDBCConnectionImpl impl = null;
						//retrieve existing unused connection
						impl = (JDBCConnectionImpl)pool.elementAt(size-1);
						//remove connection from pool
						pool.removeElementAt(size-1);
						System.out.println("current pool size:" + pool.size());
						//return connection
						return impl;
					}					
				}
				
				System.out.println("acquireImpl: pool is empty...");
				
				//pool is empty so create a new connection		
				//if(curConn < MAX_CONN)
				//{
				//	curConn++;
					return new JDBCConnectionImpl();
				//}
				
				//pool is empty and max connections reached
				//System.out.println("acquireImpl: Connection pool is full - try again");				
				//this.wait(1000);
				//return null;
								
			}
			
			//return to connection pool
			public synchronized void releaseImpl (JDBCConnectionImpl impl)
			{
				if(pool == null)
				{
					pool = new Vector();					
				} 
				System.out.println("repleaseImpl: giving connection back to pool");				
				pool.addElement(impl);
				System.out.println("current pool size:" + pool.size());
			}
			
			public void close()
			{
				if(pool != null)
				{
					int size = pool.size();
					if(size > 0)
					{						
						JDBCConnectionImpl impl = null;
						//retrieve existing unused connection
						impl = (JDBCConnectionImpl)pool.elementAt(size-1);
						//remove connection from pool
						pool.removeElementAt(size-1);
						//close connection
						impl.close();						
					}
				}
			}
			
			
		}//end Pool Class
		
		
		
		
		
		
	
}//end JDBCConnectionImpl class
	
	/* OLD CODE
	
	//************************************************	
	public JDBCConnectionImpl (String dbName) // private constructor 
	throws SQLException, ClassNotFoundException 
	//************************************************
	{ 
		this.dbName = dbName; 
		// code for creating Oracle connection 
		DBSetup dbs = new DBSetup();
		System.out.println("JDBCConnectionImpl: create jdbcconnectionimpl");

		try{
            Class.forName("org.postgresql.Driver");
        }
        catch (ClassNotFoundException cnfe)
        {
            //throw new Exception("Class!");
            System.out.println("Class not found blargh!");
            return;
        }
		
		if (dbName == dbs.GROUP_DB) 
		{ 			
			conn = DriverManager.getConnection("jdbc:postgresql://b02.seng.engr.uvic.ca/se462g02","se462g02","mvbrioeE");
			//conn = DriverManager.getConnection("jdbc:postgresql://b02.seng.engr.uvic.ca/se462g02","se462g02","mvbrioeE");
			//conn.setAutoCommit(true);
			//conn = DriverManager.getConnection ("jdbc:oracle:oci8:@", "system", "manager"); 
			System.out.println("JDBCConnectionImpl: finish jdbcconnectionimpl CREATION!");
			return; 
		}
		
		 // code for creating connections to other databases 
		// ... 
		// if database name is not found 
		throw new ClassNotFoundException("JDBCConnectionImpl: Failed to load driver"); 
		// return; 
	}
	
	//************************************************	
	String getDatabaseName() 
	//************************************************	
	{ 
		return dbName; 
	}
	
	//************************************************
	ResultSet sendRequest (String sqlString) throws SQLException 
	//************************************************
	{ 
		ResultSet rs = null;
		System.out.println("sendRequest-impl: start");		
		
		try
		{
			if (conn == null)
	        {
	            System.out.println("Connection is null");
	            return rs;
	        }

	        Statement statement = conn.createStatement();
	        rs = statement.executeQuery(sqlString);            
	        rs.first();

		}catch(SQLException sqle)
		{
			System.out.println("SQLException: " + sqle);
			
		}
		System.out.println("sendRequest: made it");
		
		return rs; 
	}
	
	//************************************************
	int sendUpdate (String sqlString) throws SQLException
	//************************************************
	{
		int result = 0;
		System.out.println("sendUpdate: start");
		
        try
        {
            Connection conn = getConnection();
            if (conn == null)
            {
                System.out.println("Connection is null");
                return result;
            }

            Statement statement = conn.createStatement();
            result = statement.executeUpdate(qry);
			conn.commit();
            System.out.println("sendUpdate: result:" + result + "");
            closeConnection(conn);
        }
        catch (SQLException sqle)
        {
            throw new SQLException("update failed" + sqle);
        }
		System.out.println("sendUpdate: end");
		
        return result;
	}
	
		
	static class JDBCPool 
	{ 
		// dictionary of database names with corresponding vector of connections 
		private Hashtable poolDictionary = new Hashtable();
		private static int maxSize = 5; //base size of one connection
		
		// methods and attributes for Singleton pattern 
		private JDBCPool() {} // private constructor 
		private static JDBCPool _instance; // get class instance 
		// Singleton getter utilizing Double Checked Locking pattern 
		//***************************************
		public static JDBCPool getInstance() 
		//***************************************		
		{ 
			System.out.println("getInstance: start");
			
			if (_instance == null) 
			{ 
				synchronized(JDBCPool.class) 
				{ 
					if (_instance == null) _instance = new JDBCPool(); 
				} 
			} 
			System.out.println("getInstance: end");
			return _instance; 
		}
		
		// get connection from pool public synchronized 
		//*************************************************************		
		JDBCConnectionImpl acquireImpl (String dbName) throws SQLException, ClassNotFoundException 
		//*************************************************************		
		{ 
			System.out.println("acquireImpl: start");
			
			// get pool matching database name 
			Vector pool = (Vector)poolDictionary.get(dbName);
			if (pool != null) 
			{ 
				int size = pool.size(); 
				//if max number of connections is at max get an existing connection
				if (size == maxSize) 
				{ 
					System.out.println("acquireImpl: retrieving existing connection");
					JDBCConnectionImpl impl = null; 
					// retrieve existing unused connection 
					impl = (JDBCConnectionImpl)pool.elementAt(size-1); 
					// remove connection from pool 
					pool.removeElementAt(size-1); 
					// return connection 
					return impl; 
				} 
			} 
			// pool is empty so create new connection 
			System.out.println("acquireImpl: creating new connection");
			return new JDBCConnectionImpl(dbName); 
		}
		
		// return connection to pool public synchronized 
		//***************************************
		void releaseImpl (JDBCConnectionImpl impl) 
		//***************************************		
		{ 
			String dbName = impl.getDatabaseName(); 
			Vector pool = (Vector)poolDictionary.get(dbName); 
			if (pool == null) 
			{ 
				pool = new Vector(); 
				poolDictionary.put(dbName, pool); 
			} 
			pool.addElement(impl); 
		} 				
		
	} 
}*/
		
		